﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BacteriaSimulation.Simulation
{
    public class CyanobacteriumSimulationStrategy : BacteriumSimulationStrategy
    {
        protected Vector2D NewSpeed = null;

        public override void PerformStrategy(Bacterium bacterium, SimulationEnvironment env)
        {
            if (bacterium.AccelerationDirection == null)
            {
                bacterium.AccelerationDirection = new UnitVector2D(bacterium.Speed.XComponent, bacterium.Speed.YComponent);
            }

            //// the bacterium cannot grow more than his MaxEnergy parameter
            //Double maxEnergyIncrement = Math.Min(bacterium.EnergyIncrement, bacterium.MaxEnergy - bacterium.Energy);
            //// the bcteriuum cannot grow more than the left avalaible energy resource in the environment
            ////maxEnergyIncrement = Math.Min(maxEnergyIncrement, env.AvalaibleEnergyResource);

            //// This "if" is just to be sure that we never exceed the maximum energy level for more than one simulation cycle
            //if (bacterium.Energy > bacterium.MaxEnergy)
            //{
            //    bacterium.Energy = bacterium.MaxEnergy;
            //}
            //else if (maxEnergyIncrement > 0)
            //{
            //    bacterium.Grow(env.ProvideEnergy(maxEnergyIncrement), env);
            //}
            env.GrowBacterium(bacterium);

            Bacterium nearestPreadator = null;
            Double nearestSquareDistance = Double.MaxValue;

            View view = bacterium.See();
            foreach (IndexGridCell cell in view.VisibleCells)
            {
                foreach (Bacterium visible in cell.Bacteria)
                {
                    if (visible == bacterium || visible.Strategy is CyanobacteriumSimulationStrategy)
                    {
                        continue;
                    }

                    double squareDistance = SimulationPoint.SquareDistance(bacterium.Position, visible.Position);
                    if (nearestPreadator == null || squareDistance < nearestSquareDistance)
                    {
                        nearestPreadator = visible;
                        nearestSquareDistance = squareDistance;
                    }
                }
            }

            if (nearestPreadator != null)
            {
                Vector2D connection = new Vector2D(nearestPreadator.X - bacterium.X, nearestPreadator.Y - bacterium.Y);
                //double angleCosine = (bacterium.Speed.XComponent * connection.XComponent + bacterium.Speed.YComponent * connection.YComponent) / bacterium.Speed.GetMagnitude() * connection.GetMagnitude();
                Vector2D rightPerpendicular = new Vector2D(connection.YComponent, -1 * connection.XComponent);
                // The value of dotProduct tells if the angle between connection and bacterium.Speed (the current direction of the bacterium)
                // is positive or negative
                double dotProduct = rightPerpendicular.XComponent * bacterium.Speed.XComponent + rightPerpendicular.YComponent * bacterium.Speed.YComponent;
                if (dotProduct < 0 + env.Epsilon)
                {
                    // the angle is negative: bacterium must turn left. the new acceleration is along the left perpendicular to the 
                    // current speed
                    bacterium.AccelerationDirection = new UnitVector2D(-1 * bacterium.Speed.YComponent, bacterium.Speed.XComponent);
                }
                else if (dotProduct > 0 + env.Epsilon)
                {
                    // the angle is positive: bacterium must turn right. the new acceleration is along the right perpendicular to the 
                    // current speed
                    bacterium.AccelerationDirection = new UnitVector2D(bacterium.Speed.YComponent, -1 * bacterium.Speed.XComponent);
                }
                else
                {
                    // the current direction is just good to get the prey
                    bacterium.AccelerationDirection = new UnitVector2D(connection.XComponent, connection.YComponent);
                }
            }
            else
            {
                //Vector2D connectionToCenter = new Vector2D(200 - bacterium.X, 200 - bacterium.Y);

                ////double angleCosine = (bacterium.Speed.XComponent * connection.XComponent + bacterium.Speed.YComponent * connection.YComponent) / bacterium.Speed.GetMagnitude() * connection.GetMagnitude();
                //Vector2D rightPerpendicular = new Vector2D(connectionToCenter.YComponent, -1 * connectionToCenter.XComponent);
                //// The value of dotProduct tells if the angle between connection and bacterium.Speed (the current direction of the bacterium)
                //// is positive or negative
                //double dotProduct = rightPerpendicular.XComponent * bacterium.Speed.XComponent + rightPerpendicular.YComponent * bacterium.Speed.YComponent;
                //if (dotProduct < 0 + env.Epsilon)
                //{
                //    bacterium.AccelerationDirection = new UnitVector2D(bacterium.Speed.YComponent, -1 * bacterium.Speed.XComponent);
                //}
                //else if (dotProduct > 0 + env.Epsilon)
                //{
                //    bacterium.AccelerationDirection = new UnitVector2D(-1 * bacterium.Speed.YComponent, bacterium.Speed.XComponent);
                //}
                //else
                //{
                //    // the current direction is just good to get to the center
                //    bacterium.AccelerationDirection = new UnitVector2D(connectionToCenter.XComponent, connectionToCenter.YComponent);
                //}
            }
        }

        public override void WallCollisionDetected(Bacterium bacterium, WALL_COLLISION_TYPE collisionType)
        {
            switch (collisionType)
            {
                case WALL_COLLISION_TYPE.BOTTOM:
                    {
                        bacterium.Speed.YComponent *= -1;
                        bacterium.AccelerationDirection.YComponent *= -1;
                        break;
                    }
                case WALL_COLLISION_TYPE.RIGHT:
                    {
                        bacterium.Speed.XComponent *= -1;
                        bacterium.AccelerationDirection.XComponent *= -1;
                        break;
                    }
                case WALL_COLLISION_TYPE.TOP:
                    {
                        bacterium.Speed.YComponent *= -1;
                        bacterium.AccelerationDirection.YComponent *= -1;
                        break;
                    }
                case WALL_COLLISION_TYPE.LEFT:
                    {
                        bacterium.Speed.XComponent *= -1;
                        bacterium.AccelerationDirection.XComponent *= -1;
                        break;
                    }
            }
        }

        public override void BacteriumCollisionDetected(Bacterium bacterium, Bacterium collidedBacterium, SimulationEnvironment env)
        {
            //if (collidedBacterium == bacterium.Brother)
            //{
            //    return;
            //}

            //NewSpeed = collidedBacterium.Speed.Clone();

        }
    }
}
